﻿/*************************************
 * Java Vector like array implementation.
 *
 * Contributors: Shawn Liu
 *
 */

module dwt.util.vector;

private import dwt.dwt;

int foo;



deprecated alias TVector VecT;

/**
 * Don't use T as simple data type, such as int, char, 
 */
template TVector(T)
{
	static boolean contains(T[] items, T element, boolean byRef = true) {

		return indexOf(items, element, byRef) >= 0;
	}

	static void sort (inout T[] items, int function(T a,T b) compareFunc)
	{
		assert(compareFunc);
		
		if(!items.length) return;
		
		T tmp;
		boolean notdone=1;
		int c=0,c2=0;
		for(;notdone;)
		{
			notdone=0;
			for(c=items.length-1;c>0;c=c2)
			{
				c2=c-1;
				if(compareFunc(items[c],items[c2])<0)
				{
					tmp=items[c2];
					items[c2]=items[c];
					items[c]=tmp;
					notdone=1;
				}
			}
		}
	}

	static boolean deleteItems(inout T[] items, int index, int len=1)
	{
		if(index<0 || index>=items.length || index+len>items.length) return false;
		if(len==0) return true;
		if(len==items.length)
		{
			items.length=0;
			return true;
		}
		items=items[0..index]~items[index+len..items.length];
		return true;
	}

	static int indexOf(T[] items, T element, boolean byRef = true) {

		for(int i=0;i <items.length; ++i){
			T t = items[i];
			if(byRef){
				if(t is element)
					return i;			
			}else if(t == element)
				return i;
		}
		return -1;
	}
	
	static T remove(inout T[] items, int index)
	{
		if(items.length == 0) {
			return null;
		}

		if(index < 0 || index >= items.length){
			debug{
				DWT.error(__FILE__, __LINE__, "Out of array bounds.");
			}
			return null;
		}
		
		T element = items[index];
		
		int length = items.length;
		if(length == 1){				
			items.length = 0;
			return element;
		}
		
		if(index == 0)
			items = items[1 .. $];
		else if(index == length - 1)
			items = items[0 .. index];
		else
			items = items[0 .. index] ~ items[index + 1 .. $];
		
		return element;
	}
	
	/**
	 * remove an item from Array, compare the item by reference or content
	 * if T is char[], you may do a string content compare by set byRef to false	
	 */
	static int remove(inout T[] items, T item, boolean byRef = true)
	{
		if(items.length == 0 || item is null) 
			return -1;
			
		for(int i = 0; i < items.length; i++){
			if(byRef){
				// do a reference compare
				if(item is items[i])
				{
					remove(items, i);
					return i;
				}
			}else if(item == items[i]) {
				// do a content compare instead of reference
				remove(items, i);
				return i;
			}
		}
		return -1;
	}
	
	
	static void insert(inout T[] items, T item, int index = -1)
	{	
		if(index == -1)
			index = items.length;
		
		if(index < 0 || index > items.length ){
			debug{
				DWT.error(__FILE__, __LINE__, "Out of array bounds.");
			}
			return;
		}
			
		if(index == items.length){
			items ~= item;
		}else if(index == 0){
			T[] newVect;
			newVect ~= item;
			items = newVect ~ items;		
		}else if(index < items.length ){
			T[] arr1 = items[0 .. index];
			T[] arr2 = items[index .. $];

			// Important : if you write like the following commented, 
			// you get wrong data
			// code:  T[] arr1 = items[0..index];
			//        T[] arr2 = items[index..$];
			//        items = arr1 ~ item;		// error, !!!
			//        items ~= arr2;			// item replace the arrr2[0] here
			items = arr1 ~ item ~ arr2;
		}
	}
	
}	// end of class TVector(T)


unittest
{
	Object[] objs = new Object[3];
	for(int i=0; i<objs.length; ++i) {
		objs[i] = new Object();
//		Util.printObj(objs[i], new String("objs") + i);
	}
	
	Object obj2 = objs[2];
	Object xx = new Object;
//	Util.printObj(xx, new String("xx"));

	TVector!(Object).insert(objs, xx, 2);
	
	
	TVector!(Object).insert(objs, xx);

	assert(obj2 is objs[3]);

//	Util.trace("\ndump 1\n");
	for(int i=0; i<objs.length; ++i){
//		Util.printObj(objs[i], new String("objs") + i);
	}

	

	TVector!(Object).remove(objs, 1);

	assert(obj2 is objs[2]);

//	Util.trace("\ndump 2\n");
	for(int i=0; i<objs.length; ++i){
//		Util.printObj(objs[i], new String("objs") + i);
	}

	TVector!(Object).remove(objs, xx);
	
//	Util.trace("\ndump 3\n");
	for(int i=0; i<objs.length; ++i){
//		Util.printObj(objs[i], new String("objs") + i);
	}

	int len = objs.length;


	char[]  c1 = "char[] 1";
	char[]  c2 = "char[]2";
	char[][] cArr;
	cArr ~= c1;
	cArr ~= c2;
	TVector!(char[]).insert(cArr, "abcd");

	assert(cArr[2] == "abcd");

}

/**
 * Java Vector like array implementation.
 * Don't use T as simple data type, such as int, char, 
 */
class Vector(T)
{
	
	private T[] _values;
	
	public this(){}
	
	public ~this() 
	{
		clear();
	}
	
	alias length getSize;
	public int length()
	{
		return _values.length;
	}
	
	
	public void length(int length) { _values.length = length;}
	
	alias addElement add;
	public void addElement(T element){_values ~= element;}
	public void addElement(int index, T element) 
	{
        insertElementAt(element, index);
    }
    public void insertElementAt(T element, int index)
	{
		TVector!(T).insert(_values, element, index);
	}
    	
    alias elementAt opIndex;
	public T elementAt(int index)
	{
		if(index < 0 || index >= length())
		{
			DWT.error(__FILE__, __LINE__, "Out of array bounds.");
			return null;
		}
		return _values[index];
	}

    
	public void setElementAt(T element, int index)
	{
		if(index < 0 || index > _values.length )
		{
			DWT.error(__FILE__, __LINE__, "Out of array bounds.");
			return;
		}
		_values[index] = element;
	}
		
	public void opIndexAssign(T value, int index)
	{	
		if(index < 0 || index >= length())
		{
			DWT.error(__FILE__, __LINE__, "Out of array bounds.");
			return;
		}	
		_values[index] = value;
	}
	
	public void opCatAssign(T element){_values ~= element;} 	
	
	alias removeElement remove;
	
	
	public void removeElement(T element)
	{
		TVector!(T).remove(_values, element);
	}
	
	public T removeElementAt(int index)
	{
		return TVector!(T).remove(this._values, index);
	}
	
	public T[] values(){ return _values[];}


	public boolean contains(T element)
	{
		foreach(T t; _values){
			if(t is element)
				return true;			
		}
		return false;			
	}

	public void clear() { _values.length = 0;}
	
}


